// 简易版响应式系统实现
const targetMap = new WeakMap(); // 存储依赖关系的全局变量
let activeEffect = null; // 当前激活的副作用函数 effect
const effectStack = []; // 副作用函数栈,用于处理嵌套的 effect

// 1.// 副作用函数 effect
function effect(fn, options = {}) {
    const effectFn = () => {
        try {
            // 入栈
            effectStack.push(effectFn);
            // 设置当前effect
            activeEffect = effectFn;
            // 执行原始函数，触发依赖收集
            return fn();
        } finally {
            // 出栈
            effectStack.pop();
            // 恢复之前的effect
            activeEffect = effectStack[effectStack.length - 1];
        }
    };
    // 挂载调度器和其他选项
    effectFn.scheduler = options.scheduler;
    effectFn.lazy = options.lazy;

    // 如果不是懒执行，则立即执行
    if (!options.lazy) {
        effectFn();
    }
    return effectFn;
}

// 2. 依赖收集-track
function track(target, key) {
    // 如果没有激活的effect，则不需要收集依赖
    if (!activeEffect) return;
    // 获取target对应的依赖集合
    let depsMap = targetMap.get(target);
    if (!depsMap) {
        // 如果不存在，则创建一个新的依赖集合
        targetMap.set(target, (depsMap = new Map()));
    }
    // 获取key对应的依赖集合
    let dep = depsMap.get(key);
    if (!dep) {
        // 如果不存在，则创建一个新的依赖集合
        depsMap.set(key, (dep = new Set()));
    }
    // 将当前激活的effect添加到依赖集合中
    dep.add(activeEffect);
    /**
	 * targetMap 结构如下:
	 * targetMap:{
	    target1: {
	      key1: [effect1, effect2],
	    }
	   }
	 */
    console.log(
        `📌 收集依赖: ${String(key)} ->`,
        activeEffect.name || "anonymous"
    );
}

// 3. 触发更新- trigger
function trigger(target, key) {
    // 获取target对应的依赖集合
    const depsMap = targetMap.get(target);
    if (!depsMap) return;

    // 获取key对应的依赖集合
    const dep = depsMap.get(key);
    if (!dep) return;
    console.log(`🚀 触发更新: ${String(key)}，共有 ${dep.size} 个依赖`);

    // 创建一个Set，用于存储需要执行的effect,避免重复执行
    const effectsToRun = new Set();
    // 遍历依赖集合，执行每个effect
    dep.forEach((effect) => {
        effectsToRun.add(effect);
    });
    effectsToRun.forEach((effect) => {
        if (effect.scheduler) {
            // 如果有调度器，则使用调度器执行effect，调度器主要用于异步更新页面
            effect.scheduler();
        } else {
            // 否则直接执行effect
            effect();
        }
    });
}

// 4. reactive 实现
function reactive(target) {
    return new Proxy(target, {
        get(target, key, receiver) {
            console.log(`🔍 读取属性: ${String(key)} = ${target[key]}`);
            const result = Reflect.get(target, key, receiver);
            // 依赖收集
            track(target, key);
            if (typeof result === "object" && result !== null) {
                return reactive(result);
            }

            return result;
        },
        set(target, key, value, receiver) {
            console.log(`✏️ 设置属性: ${String(key)} = ${value}`);
            const oldValue = target[key];
            const result = Reflect.set(target, key, value, receiver);
            // 只有值真正改变时才触发更新;
            if (oldValue !== value) {
                trigger(target, key);
            }

            return result;
        },
    });
}

// 5. ref 实现
function ref(value) {
    const refObject = {
        get value() {
            track(refObject, "value");
            return value;
        },
        set value(newValue) {
            if (value !== newValue) {
                value = newValue;
                trigger(refObject, "value");
            }
        },
    };
    return refObject;
}

// 组件渲染里面
// 调度器的作用：异步更新，避免重复渲染
// Promise.resolve().then(() => this._update());

// 6. computed 实现
function computed(getter) {
    let dirty = true; // 是否需要重新计算
    let value; // 计算属性的值
    let computedRef = ref(); // 计算属性的引用对象

    /**
     *例子： getter:()=>count.value*2;
     * lazy为true，所以刚创建computed的时候，不会立即执行getter函数，而是将getter函数赋值给computedRef.value，
     * 当访问computedRef.value的时候，dirty为ture,触发runner函数(getter)，getter函数读取了count.value,
     * count对应的track会收集依赖activeEffect，
     * 而此时的activeEffect是包含getter的effectFn和对应的scheduler
     * 当count.value改变的时候，会触发trigger，从而执行scheduler，scheduler中会判断dirty，
     * 如果dirty为true，则执行runner函数，
     */
    const runner = effect(getter, {
        lazy: true, // 懒执行
        scheduler: () => {
            // 调度器的作用：
            if (!dirty) {
                dirty = true;
                trigger(computedRef, "value");
            }
        },
    });

    //将 runner 函数赋值给 computedRef.value，以便在访问 computedRef.value 时执行 runner 函数
    Object.defineProperty(computedRef, "value", {
        get() {
            if (dirty) {
                value = runner();
                dirty = false;
                track(computedRef, "value");
            }
            return value;
        },
    });
    return computedRef;
}

function watch(source, cb, options = {}) {
    let getter;
    if (typeof source === "function") {
        getter = source;
    } else {
        getter = () => source;
    }
    let oldValue;
    const job = () => {
        const newValue = effectFn();
        cb(newValue, oldValue);
        oldValue = newValue;
    };
    const effectFn = effect(getter, {
        lazy: true,
        scheduler: job,
    });
    oldValue = effectFn();
}

// 测试用例
// console.log("=== 测试基础响应式 ===");
// const state = reactive({
//     count: 0,
//     user: { name: "张三" },
// });

// // effect 1-基础使用
// effect(() => {
//     const v = state.count;
//     console.log(`🎯 effect1: count = ${v}`);
// });
// // effect 2-嵌套对象
// effect(() => {
//     console.log(`🎯 effect2: user.name = ${state.user.name}`);
// })

// console.log("--- 修改 count ---");
// state.count = 1;// 触发effect 1

// console.log("--- 修改 user.name ---");
// state.user.name = "Bob";// 触发effect 2

// console.log("\n=== 测试嵌套 effect ===");
// const nestedState = reactive({
//     a: 1,
//     b: 2,
//     c: 3,
// });

// // 外层 effect
// effect(function outerEffect() {
//   console.log(`🔄 外层 effect: a = ${nestedState.a}`)

//   // 内层 effect - 嵌套！
//   effect(function innerEffect() {
//     console.log(`  🔄 内层 effect: b = ${nestedState.b}`)
//   })

//   console.log(`🔄 外层 effect 继续: c = ${nestedState.c}`)
// })

// console.log("--- 测试嵌套场景下的依赖收集 ---");
// console.log("修改 b (应该只触发内层 effect):");
// nestedState.b = 20;

// console.log("修改 a (应该触发外层 effect，重新执行内外层):");
// nestedState.a = 10;

// console.log("\n=== 测试 ref 和 computed ===");
// const countRef = ref(0);
// const doubleCount = computed(() => {
//     console.log("🔄 computed 重新计算");
//     return countRef.value * 2;
// });

// effect(() => {
//     console.log(`📊 computed 值: ${doubleCount.value}`);
// });
// console.log("修改 ref 值:");
// countRef.value = 5;
